package xin.nick.system.service;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import xin.nick.common.core.constant.SystemConstants;
import xin.nick.common.core.entity.ResultCode;
import xin.nick.common.core.util.MyAssert;
import xin.nick.system.entity.SystemAuthority;
import xin.nick.system.entity.SystemRole;
import xin.nick.system.entity.SystemUser;
import xin.nick.system.manager.SystemAuthorityManager;
import xin.nick.system.manager.SystemRoleManager;
import xin.nick.system.manager.SystemUserManager;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author Nick
 * @since 2022/7/21/021
 */
@Component
@Slf4j
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class MyUserDetailsService implements UserDetailsService {

    private final SystemUserManager systemUserManager;
    private final SystemAuthorityManager systemAuthorityManager;
    private final SystemRoleManager roleManager;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        MyAssert.isTrue(StringUtils.hasLength(username), "username不可为空");
        log.info("用户开始登陆: {}", username);

        return getLoginUserByUsername(username);
    }

    /**
     * 根据用户名获取登录用户信息
     *
     * @param username String
     * @return LoginUser
     */
    private UserDetails getLoginUserByUsername(String username) {
        // 获取用户信息,封装成 UserDetails 对象
        LambdaQueryWrapper<SystemUser> systemUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        systemUserLambdaQueryWrapper
                .eq(SystemUser::getUsername, username)
                .eq(SystemUser::getDisabled, false);
        SystemUser systemUser = systemUserManager.getListFirst(systemUserLambdaQueryWrapper);
        MyAssert.notNull(systemUser, ResultCode.ACCOUNT_OR_PASSWORD_ERROR);
        String userPassword = systemUser.getPassword();
        String dbUsername = systemUser.getUsername();
        // 数据库内容未区分大小写,这里查出来再匹配一次
        MyAssert.isTrue(StrUtil.equals(dbUsername, username), ResultCode.ACCOUNT_OR_PASSWORD_ERROR);

        // 返回 UserDetails 对象  // 这里可以利用 Security 对账号的 是否生效,是否过期,是否校验过期,是否锁定 状态进行控制
        // 根据用户获取权限信息
        List<SimpleGrantedAuthority> authorityList = getAuthorityList(systemUser.getUserId());
        return new User(dbUsername, userPassword, authorityList);
    }

    /**
     * 根据管理员id获取权限列表
     *
     * @param userId Long
     * @return List<String>
     */
    public List<SimpleGrantedAuthority> getAuthorityList(Long userId) {

        // 所有权限信息
        List<SimpleGrantedAuthority> allAuthorityList = new ArrayList<>();

        // 角色列表
        List<SystemRole> roleList = roleManager.getRoleListByUserId(userId);

        // 角色权限信息放入所有权限列表
        for (SystemRole role : roleList) {

            // 禁用的不加入
            Boolean disabled = Optional.ofNullable(role.getDisabled()).orElse(true);
            if (disabled) {
                continue;
            }

            // 角色 key
            String roleKey = role.getRoleKey();
            if (StrUtil.isBlank(roleKey)) {
                continue;
            }
            allAuthorityList.add(genSimpleGrantedAuthority(roleKey));
        }

        // 根据角色id获取到权限列表
        List<Long> roleIdList = roleList.stream()
                .filter(Objects::nonNull)
                // 去掉被禁用的角色
                .filter(role -> !Optional.ofNullable(role.getDisabled()).orElse(true))
                .map(SystemRole::getRoleId)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        List<SystemAuthority> authorityList = systemAuthorityManager.getAuthorityListByRoleIdList(roleIdList);

        // 所有权限列表
        for (SystemAuthority authority : authorityList) {

            // 禁用的不加入
            Boolean disabled = Optional.ofNullable(authority.getDisabled()).orElse(true);
            if (disabled) {
                continue;
            }

            // 权限key
            String authorityKey = authority.getAuthorityKey();
            if (StringUtils.hasLength(authorityKey)) {
                allAuthorityList.add(new SimpleGrantedAuthority(authorityKey));
            }
        }

        // 如果是指定超管的话,添加超管角色
        if (systemUserManager.isRoot(userId)) {
            allAuthorityList.add(new SimpleGrantedAuthority(SystemConstants.ROOT_ROLE));
        }

        return allAuthorityList;
    }

    /**
     * 因为security自身的设计原因，我们在用户分组和角色权限，增加ROLE前缀
     *
     * @param role 角色
     * @return SimpleGrantedAuthority
     */
    private SimpleGrantedAuthority genSimpleGrantedAuthority(String role) {
        if (!role.startsWith(SystemConstants.ROLE_PREFIX)) {
            role = SystemConstants.ROLE_PREFIX + role;
        }
        return new SimpleGrantedAuthority(role);
    }

}
